/***********************************************************************************************************************
*  OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
*  See also https://openstudio.net/license
***********************************************************************************************************************/

#include "AirflowNetworkEquivalentDuct.hpp"
#include "AirflowNetworkEquivalentDuct_Impl.hpp"

#include "StraightComponent.hpp"
#include "StraightComponent_Impl.hpp"

#include <utilities/idd/IddFactory.hxx>
#include <utilities/idd/IddEnums.hxx>
#include <utilities/idd/OS_AirflowNetworkEquivalentDuct_FieldEnums.hxx>

#include "../utilities/units/Unit.hpp"

#include "../utilities/core/Assert.hpp"

namespace openstudio {
namespace model {

  namespace detail {

    AirflowNetworkEquivalentDuct_Impl::AirflowNetworkEquivalentDuct_Impl(const IdfObject& idfObject, Model_Impl* model, bool keepHandle)
      : AirflowNetworkComponent_Impl(idfObject, model, keepHandle) {
      OS_ASSERT(idfObject.iddObject().type() == AirflowNetworkEquivalentDuct::iddObjectType());
    }

    AirflowNetworkEquivalentDuct_Impl::AirflowNetworkEquivalentDuct_Impl(const openstudio::detail::WorkspaceObject_Impl& other, Model_Impl* model,
                                                                         bool keepHandle)
      : AirflowNetworkComponent_Impl(other, model, keepHandle) {
      OS_ASSERT(other.iddObject().type() == AirflowNetworkEquivalentDuct::iddObjectType());
    }

    AirflowNetworkEquivalentDuct_Impl::AirflowNetworkEquivalentDuct_Impl(const AirflowNetworkEquivalentDuct_Impl& other, Model_Impl* model,
                                                                         bool keepHandle)
      : AirflowNetworkComponent_Impl(other, model, keepHandle) {}

    const std::vector<std::string>& AirflowNetworkEquivalentDuct_Impl::outputVariableNames() const {
      static const std::vector<std::string> result;
      return result;
    }

    IddObjectType AirflowNetworkEquivalentDuct_Impl::iddObjectType() const {
      return AirflowNetworkEquivalentDuct::iddObjectType();
    }

    boost::optional<StraightComponent> AirflowNetworkEquivalentDuct_Impl::straightComponent() const {
      return getObject<ModelObject>().getModelObjectTarget<StraightComponent>(OS_AirflowNetworkEquivalentDuctFields::ComponentName);
    }

    boost::optional<std::string> AirflowNetworkEquivalentDuct_Impl::coilObjectType() const {
      auto optsc = straightComponent();
      if (optsc) {
        switch (optsc->iddObjectType().value()) {
          case IddObjectType::OS_Coil_Cooling_DX_SingleSpeed:
            return std::string("Coil:Cooling:DX:SingleSpeed");
          case IddObjectType::OS_Coil_Cooling_DX_TwoSpeed:
            return std::string("Coil:Cooling:DX:TwoSpeed");
          case IddObjectType::OS_Coil_Heating_Gas:
            return std::string("Coil:Heating:Fuel");
          case IddObjectType::OS_Coil_Heating_Electric:
            return std::string("Coil:Heating:Electric");
          case IddObjectType::OS_Coil_Heating_DX_SingleSpeed:
            return std::string("Coil:Heating:DX:SingleSpeed");
          case IddObjectType::OS_Coil_Cooling_Water:
            return std::string("Coil:Cooling:Water");
          case IddObjectType::OS_Coil_Heating_Water:
            return std::string("Coil:Heating:Water");
          //case IddObjectType::Coil_Cooling_Water_DetailedGeometry:
          //  return std::string("Coil:Cooling:Water:DetailedGeometry");
          case IddObjectType::OS_Coil_Cooling_DX_TwoStageWithHumidityControlMode:
            return std::string("Coil:Cooling:DX:TwoStageWithHumidityControlMode");
          case IddObjectType::OS_Coil_Cooling_DX_MultiSpeed:
            return std::string("Coil:Cooling:DX:MultiSpeed");
          case IddObjectType::OS_Coil_Heating_DX_MultiSpeed:
            return std::string("Coil:Heating:DX:MultiSpeed");
          case IddObjectType::OS_Coil_Cooling_DX_VariableSpeed:
            return std::string("Coil:Cooling:DX:VariableSpeed");
          case IddObjectType::OS_Coil_Heating_DX_VariableSpeed:
            return std::string("Coil:Heating:DX:VariableSpeed");
          case IddObjectType::OS_Coil_Heating_Desuperheater:
            return std::string("Coil:Heating:Desuperheater");
          case IddObjectType::OS_Coil_Cooling_DX:
            return std::string("Coil:Cooling:DX");
          case IddObjectType::OS_Coil_Cooling_DX_SingleSpeed_ThermalStorage:
            return std::string("Coil:Cooling:DX:SingleSpeed:ThermalStorage");
          case IddObjectType::OS_Coil_Cooling_WaterToAirHeatPump_EquationFit:
            return std::string("Coil:Cooling:WaterToAirHeatPump:EquationFit");
          case IddObjectType::OS_Coil_Heating_WaterToAirHeatPump_EquationFit:
            return std::string("Coil:Heating:WaterToAirHeatPump:EquationFit");
          case IddObjectType::OS_Coil_Cooling_WaterToAirHeatPump_VariableSpeedEquationFit:
            return std::string("Coil:Cooling:WaterToAirHeatPump:VariableSpeedEquationFit");
          case IddObjectType::OS_Coil_Heating_WaterToAirHeatPump_VariableSpeedEquationFit:
            return std::string("Coil:Heating:WaterToAirHeatPump:VariableSpeedEquationFit");
          default:
            return boost::none;
        }
      }
      return boost::none;
    }

    boost::optional<std::string> AirflowNetworkEquivalentDuct_Impl::heatExchangerObjectType() const {
      auto optsc = straightComponent();
      if (optsc) {
        switch (optsc->iddObjectType().value()) {
          //case IddObjectType::HeatExchanger_AirToAir_FlatPlate:
          //  return std::string("HeatExchanger:AirToAir:FlatPlate");
          case IddObjectType::OS_HeatExchanger_AirToAir_SensibleAndLatent:
            return std::string("HeatExchanger:AirToAir:SensibleAndLatent");
          //case IddObjectType::HeatExchanger_Desiccant_BalancedFlow:
          //  return std::string("HeatExchanger:Desiccant:BalancedFlow");
          default:
            return boost::none;
        }
      }
      return boost::none;
    }

    boost::optional<std::string> AirflowNetworkEquivalentDuct_Impl::terminalUnitObjectType() const {
      auto optsc = straightComponent();
      if (optsc) {
        switch (optsc->iddObjectType().value()) {
          case IddObjectType::OS_AirTerminal_SingleDuct_ConstantVolume_Reheat:
            return std::string("AirTerminal:SingleDuct:ConstantVolume:Reheat");
          case IddObjectType::OS_AirTerminal_SingleDuct_VAV_Reheat:
            return std::string("AirTerminal:SingleDuct:VAV:Reheat");
          default:
            return boost::none;
        }
      }
      return boost::none;
    }

    boost::optional<ModelObject> AirflowNetworkEquivalentDuct_Impl::componentModelObject() const {
      return getObject<ModelObject>().getModelObjectTarget<ModelObject>(OS_AirflowNetworkEquivalentDuctFields::ComponentName);
    }

    double AirflowNetworkEquivalentDuct_Impl::airPathLength() const {
      boost::optional<double> value = getDouble(OS_AirflowNetworkEquivalentDuctFields::AirPathLength, true);
      OS_ASSERT(value);
      return value.get();
    }

    double AirflowNetworkEquivalentDuct_Impl::airPathHydraulicDiameter() const {
      boost::optional<double> value = getDouble(OS_AirflowNetworkEquivalentDuctFields::AirPathHydraulicDiameter, true);
      OS_ASSERT(value);
      return value.get();
    }

    bool AirflowNetworkEquivalentDuct_Impl::setAirPathLength(double airPathLength) {
      bool result = setDouble(OS_AirflowNetworkEquivalentDuctFields::AirPathLength, airPathLength);
      return result;
    }

    bool AirflowNetworkEquivalentDuct_Impl::setAirPathHydraulicDiameter(double airPathHydraulicDiameter) {
      bool result = setDouble(OS_AirflowNetworkEquivalentDuctFields::AirPathHydraulicDiameter, airPathHydraulicDiameter);
      return result;
    }

    void AirflowNetworkEquivalentDuct_Impl::resetComponent() {
      bool result = setString(OS_AirflowNetworkEquivalentDuctFields::ComponentName, "");
      OS_ASSERT(result);
    }

  }  // namespace detail

  AirflowNetworkEquivalentDuct::AirflowNetworkEquivalentDuct(const Model& model, double length, double diameter, const Handle& handle)
    : AirflowNetworkComponent(AirflowNetworkEquivalentDuct::iddObjectType(), model) {
    OS_ASSERT(getImpl<detail::AirflowNetworkEquivalentDuct_Impl>());
    bool ok = getImpl<detail::AirflowNetworkEquivalentDuct_Impl>()->setPointer(OS_AirflowNetworkEquivalentDuctFields::ComponentName, handle);
    OS_ASSERT(ok);
    ok = setAirPathLength(length);
    OS_ASSERT(ok);
    ok = setAirPathHydraulicDiameter(diameter);
    OS_ASSERT(ok);
  }

  IddObjectType AirflowNetworkEquivalentDuct::iddObjectType() {
    return {IddObjectType::OS_AirflowNetworkEquivalentDuct};
  }

  boost::optional<StraightComponent> AirflowNetworkEquivalentDuct::straightComponent() const {
    return getImpl<detail::AirflowNetworkEquivalentDuct_Impl>()->straightComponent();
  }

  boost::optional<std::string> AirflowNetworkEquivalentDuct::coilObjectType() const {
    return getImpl<detail::AirflowNetworkEquivalentDuct_Impl>()->coilObjectType();
  }

  boost::optional<std::string> AirflowNetworkEquivalentDuct::heatExchangerObjectType() const {
    return getImpl<detail::AirflowNetworkEquivalentDuct_Impl>()->heatExchangerObjectType();
  }

  boost::optional<std::string> AirflowNetworkEquivalentDuct::terminalUnitObjectType() const {
    return getImpl<detail::AirflowNetworkEquivalentDuct_Impl>()->terminalUnitObjectType();
  }

  double AirflowNetworkEquivalentDuct::airPathLength() const {
    return getImpl<detail::AirflowNetworkEquivalentDuct_Impl>()->airPathLength();
  }

  double AirflowNetworkEquivalentDuct::airPathHydraulicDiameter() const {
    return getImpl<detail::AirflowNetworkEquivalentDuct_Impl>()->airPathHydraulicDiameter();
  }

  bool AirflowNetworkEquivalentDuct::setAirPathLength(double airPathLength) {
    return getImpl<detail::AirflowNetworkEquivalentDuct_Impl>()->setAirPathLength(airPathLength);
  }

  bool AirflowNetworkEquivalentDuct::setAirPathHydraulicDiameter(double airPathHydraulicDiameter) {
    return getImpl<detail::AirflowNetworkEquivalentDuct_Impl>()->setAirPathHydraulicDiameter(airPathHydraulicDiameter);
  }

  void AirflowNetworkEquivalentDuct::resetComponent() {
    getImpl<detail::AirflowNetworkEquivalentDuct_Impl>()->resetComponent();
  }

  /// @cond
  AirflowNetworkEquivalentDuct::AirflowNetworkEquivalentDuct(std::shared_ptr<detail::AirflowNetworkEquivalentDuct_Impl> impl)
    : AirflowNetworkComponent(impl) {}
  /// @endcond

}  // namespace model
}  // namespace openstudio
